All files / src/app/api/dev/tickets/[id]/hierarchy route.ts

0% Statements 0/89
100% Branches 0/0
0% Functions 0/1
0% Lines 0/89

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90                                                                                                                                                                                   
export const dynamic = "force-dynamic";

/**
 * Dev Ticket Hierarchy API
 * GET /api/dev/tickets/[id]/hierarchy - Get ticket hierarchy tree
 */

import { NextRequest, NextResponse } from 'next/server';
import { } from "next-auth";
import {
  withAdmin,
  withErrorHandling,
  successResponse,
  ApiError,
  ApiSuccessResponse,
  ApiErrorResponse } from "@/lib/api";
import { RouteContext } from "@/lib/api/middleware";
import { prisma } from '@/lib/prisma';
import {
  buildHierarchyTree,
  getTicketAncestors,
  calculateHierarchyProgress,
  getTicketChildren } from '@/lib/dev-ticket';

interface RouteParams {
  params: Promise<{ id: string }>;
}

async function handleGet(
  request: NextRequest,
  context: RouteContext | undefined
): Promise<NextResponse<ApiSuccessResponse<unknown> | ApiErrorResponse>> {
  const { id } = await (context as RouteParams).params;
  const { searchParams } = new URL(request.url);
  const includeTree = searchParams.get('tree') === 'true';
  const includeProgress = searchParams.get('progress') === 'true';
  const maxDepth = parseInt(searchParams.get('maxDepth') || '5', 10);

  // Verify ticket exists
  const ticket = await prisma.devTicket.findUnique({
    where: { id },
    select: {
      id: true,
      ticketNumber: true,
      title: true,
      status: true,
      category: true,
      parentId: true,
      childCount: true,
      completedChildCount: true,
      hierarchyLevel: true,
      hierarchyPath: true } });

  if (!ticket) {
    throw ApiError.notFound('Ticket not found');
  }

  // Get ancestors (breadcrumb)
  const ancestors = await getTicketAncestors(id);

  // Get direct children
  const children = await getTicketChildren(id);

  // Build response
  const responseData: {
    ticket: typeof ticket;
    ancestors: typeof ancestors;
    children: typeof children;
    tree?: Awaited<ReturnType<typeof buildHierarchyTree>>;
    progress?: Awaited<ReturnType<typeof calculateHierarchyProgress>>;
  } = {
    ticket,
    ancestors,
    children };

  // Optionally include full tree
  if (includeTree) {
    responseData.tree = await buildHierarchyTree(id, maxDepth);
  }

  // Optionally include progress calculation
  if (includeProgress) {
    responseData.progress = await calculateHierarchyProgress(id);
  }

  return successResponse(responseData);
}

export const GET = withErrorHandling(withAdmin(handleGet));